import 'dart:async';
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_common_app/data/response_data.dart';
import 'package:flutter_common_app/env/env_config.dart';
import 'package:flutter_common_app/router/routes.dart';
import 'package:flutter_common_app/utils/http/http_util.dart';
import 'package:flutter_common_app/utils/common_util/log_util.dart';
import 'package:flutter_common_app/utils/common_util/toast.dart';
import 'package:flutter_common_app/utils/user_util.dart';
import 'package:flutter_common_app/widgets/dialog/loading_controller.dart';

abstract class BaseApi {
  BaseApi(this.context) {
    _loadingController = LoadingController(context);

    _dio.options.receiveTimeout = 100000;
    _dio.options.connectTimeout = 100000;
    _dio.options.contentType = Headers.jsonContentType;

    if (!EnvConfig.isProd()) {
      _dio.interceptors.add(
        LogInterceptor(requestBody: true, responseBody: true),
      );
    }

    _dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) {
          return handler.next(options);
        },
        onResponse: (response, handler) {
          if (fromResponseData != null) {
            response.data = fromResponseData(response.data);
          }
          return handler.next(response);
        },
        onError: (DioError e, handler) {
          return handler.next(e);
        },
      ),
    );
  }

  final Map<String, dynamic> _params = <String, dynamic>{};

  LoadingController _loadingController;

  String _loadingText = '加载中...';

  final Dio _dio = Dio();

  BuildContext context;

  Map<String, dynamic> requestParams = {};

  String getMethod() {
    return HttpUtil.MethodGet;
  }

  String getPath();

  bool isShowLoading();

  bool isErrorToast() {
    return true;
  }

  Map<String, dynamic> getParams() {
    return _params;
  }

  void setLoadingText(String text) {
    _loadingText = text;
  }

  ///处理api返回结果为{'data':{},'code':200}格式
  Function fromResponseData;

  void onGetErrorFromServer(error) {
    ResponseData responseData = error.error;
    Toast.showImportant(responseData.msg);
  }

  Future<Response> send({CancelToken cancelToken}) async {
    if (isShowLoading()) {
      _loadingController.show(_loadingText);
    }

    String path;
    if (getPath().startsWith('http')) {
      path = getPath();
    } else {
      path = HttpUtil.getBaseUrl() + getPath();
    }

    requestParams = _params;

    HttpUtil.getRequestParams(context, requestParams);

    if (getMethod() == HttpUtil.MethodGet) {
      requestParams.forEach((key, value) {
        if (path.contains('?')) {
          path += '&$key=$value';
        } else {
          path += '?$key=$value';
        }
      });
    }

    _dio.options.method = getMethod();

    Future<Response> result = _dio.request(path,
        data: jsonEncode(requestParams), cancelToken: cancelToken);

    result.catchError((error) {
      onErrorToast(error);
    }).whenComplete(() {
      if (isShowLoading()) _loadingController.complete();
    });

    return result;
  }

  onErrorToast(error) {
    LogUtil.e('error:$error');
    if (isErrorToast()) {
      if (error is DioError) {
        if (CancelToken.isCancel(error)) {
          LogUtil.v('request is cancel');
        } else if (error.error is ResponseData) {
          onGetErrorFromServer(error);
        } else if (error.type == DioErrorType.connectTimeout ||
            error.type == DioErrorType.receiveTimeout ||
            error.type == DioErrorType.sendTimeout) {
          Toast.showImportant('连接超时，请检查网络！');
        } else if (error.type == DioErrorType.receiveTimeout) {
          Toast.showImportant('服务器异常，请稍候再试！');
        } else {
          Toast.showImportant('出错了，请检查网络！');
        }
        // 301 重新登录
        if (error.response.data['code'] == 301) {
          UserUtil.logout(context);
          Toast.show(error.response.data['msg']);
          Timer(Duration(seconds: 2), () {
            Navigator.pushNamedAndRemoveUntil(
                context, Routes.login, (route) => route.isFirst);
          });
          return;
        }
      } else {
        Toast.showImportant('出错了，请检查网络！');
      }
    }
  }
}
